package com.sttg.csp.common.util;

import java.io.InputStream;
import java.util.Properties;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;

public class ThreeDES {

	private final static String Algorithm = "DESede";

	final static byte[] initkeyBytes = { 0x12, 0x34, 0x56, 0x78, 0x09, (byte) 0xab, (byte) 0xcd, (byte) 0xef, (byte) 0xfe, (byte) 0xdc, (byte) 0xba, (byte) 0x90, (byte) 0x87, 0x65, 0x43, 0x21, (byte) 0xef, (byte) 0xcd, (byte) 0xab, 0x09, 0x78, 0x56, 0x34, 0x12 };

	private static Properties prop = new Properties();
	static {
		try {
			// 构造输入流读取config.properties文件
			InputStream in = ThreeDES.class.getClassLoader().getResourceAsStream("config.properties");
			prop.load(in);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 加密指定的内容<br>
	 * <b>注意：3DES加密key从指定的文件中读取
	 * 
	 * @param str 需要加密的内容字符串
	 * @return 加密后的内容
	 */
	public static String encrypt(String str) {
		return encrypt(str, getThreeDESKey());
	}

	/**
	 * 解密指定的内容<br>
	 * <b>注意：3DES加密key从指定的文件中读取
	 * 
	 * @param encryptStr 需要解密的加密字符串
	 * @return 解密后的内容
	 */
	public static String decrypt(String encryptStr) {
		return decrypt(encryptStr, getThreeDESKey());
	}

	/**
	 * 根据指定的3DES加密key，加密指定的内容
	 * 
	 * @param str 需要加密的内容字符串
	 * @param key 3DES加密key
	 * @return 加密后的内容
	 */
	private static String encrypt(String str, String key) {
		try {
			// 根据初始密钥key，解密存放在文件中的加密key为明文key
			SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(Algorithm);
			DESedeKeySpec initDESedeKey = new DESedeKeySpec(initkeyBytes);
			SecretKey initSecretKey = keyFactory.generateSecret(initDESedeKey);

			Cipher deInitCipher = Cipher.getInstance(Algorithm);
			deInitCipher.init(Cipher.DECRYPT_MODE, initSecretKey);
			byte[] keyBytes = deInitCipher.doFinal(asc2bcd(key));

			// 解密存放在文件中的加密key为明文key后，根据该明文key，加密内容
			DESedeKeySpec specDESedeKey = new DESedeKeySpec(keyBytes);
			SecretKey specSecretKey = keyFactory.generateSecret(specDESedeKey);

			Cipher enSpecCipher = Cipher.getInstance(Algorithm);
			enSpecCipher.init(Cipher.ENCRYPT_MODE, specSecretKey);
			return bcd2asc(enSpecCipher.doFinal(str.getBytes()));
		} catch (java.lang.Exception e3) {
			e3.printStackTrace();
			return null;
		}
	}

	/**
	 * 根据指定的3DES加密key，解密指定的加密内容
	 * 
	 * @param encrptStr 加密的内容字符串
	 * @param key 3DES加密key
	 * @return 解密的字符串
	 */
	private static String decrypt(String encrptStr, String key) {
		try {
			// 根据初始密钥key，解密存放在文件中的加密key为明文key
			SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(Algorithm);
			DESedeKeySpec initDESedeKey = new DESedeKeySpec(initkeyBytes);
			SecretKey initSecretKey = keyFactory.generateSecret(initDESedeKey);

			Cipher deInitCipher = Cipher.getInstance(Algorithm);
			deInitCipher.init(Cipher.DECRYPT_MODE, initSecretKey);
			byte[] keyBytes = deInitCipher.doFinal(asc2bcd(key));

			// 解密存放在文件中的加密key为明文key后，根据该明文key，加密内容
			DESedeKeySpec specDESedeKey = new DESedeKeySpec(keyBytes);
			SecretKey specSecretKey = keyFactory.generateSecret(specDESedeKey);

			Cipher deSpecCipher = Cipher.getInstance(Algorithm);
			deSpecCipher.init(Cipher.DECRYPT_MODE, specSecretKey);

			return new String(deSpecCipher.doFinal(asc2bcd(encrptStr)));
		} catch (java.lang.Exception e3) {
			e3.printStackTrace();
			return null;
		}

	}

	private static String getThreeDESKey() {
		String key = prop.getProperty("3des.key");
		if (key == null || "".equals(key)) {
			throw new IllegalArgumentException("3des.key not found!");
		}
		return key;
	}
	
	private static byte[] asc2bcd(String hexstr) {
		if (hexstr.length() % 2 != 0)
			hexstr = hexstr + "0";
		byte[] bytes = new byte[hexstr.length() / 2];
		for (int i = 0; i < hexstr.length() / 2; i++) {
			byte[] temp = new byte[2];
			temp[0] = (byte) hexstr.charAt(i * 2);
			temp[1] = (byte) hexstr.charAt(i * 2 + 1);
			bytes[i] = (byte) (Integer.parseInt(new String(temp), 16));
		}
		return bytes;
	}

	private static String bcd2asc(byte[] b) {
		String hs = "";
		String stmp = "";

		for (int n = 0; n < b.length; n++) {
			stmp = (java.lang.Integer.toHexString(b[n] & 0XFF));
			if (stmp.length() == 1)
				hs = hs + "0" + stmp;
			else
				hs = hs + stmp;
		}
		return hs.toUpperCase();
	}

}
